#include <SDL2/SDL.h>
#include <xgba_input.h>

#ifndef XGBA_VERSION
#define XGBA_VERSION "0.0.1"
#endif

typedef struct{
    const char* rom;
    const char* bios_file;
    const char* volnum;
}game_opt_t;

typedef struct game_param_t{
    const char*opt;
    void (*proc)(struct game_param_t*p,int argc,char**argv,int *index);
}game_param_t;

game_opt_t game_opt;

static void set_rom(game_param_t*p,int argc,char**argv,int *index){
    int idx = *index;
    game_opt.rom = argv[idx];
    idx+=1;
    *index = idx;
}

static void set_bios(game_param_t*p,int argc,char**argv,int *index){
    int idx = *index;
    if(argv[idx][2]==0){
        game_opt.bios_file = argv[idx+1];
        idx+=2;
    }
    else{
        game_opt.bios_file = argv[idx]+2;
        idx+=1;
    }
    *index = idx;
}

static void set_volume(game_param_t*p,int argc,char**argv,int *index){
    int idx = *index;
    if(argv[idx][2]==0){
        game_opt.volnum = argv[idx+1];
        idx+=2;
    }
    else{
        game_opt.volnum = argv[idx]+2;
        idx+=1;
    }
    *index = idx;
}

static void version(game_param_t*p,int argc,char**argv,int *index){
    fprintf(stderr,"version:%s",XGBA_VERSION);
    *index += 1;
}

static void help(game_param_t*p,int argc,char**argv,int *index){
    *index += 1;
}

game_param_t params[] = {
    {"",set_rom},
    {"-b",set_bios},
    {"-v",version},
    {"-h",help},
    {"-V",set_volume},
    {0,0},
};

#include <xgba.h>
#include <stdio.h>

typedef struct{
    SDL_Window      *window;
    SDL_Renderer    *renderer;
    SDL_Texture     *texture;
    SDL_Texture     *tileTexture;
    SDL_Event       event;
}xgba_sdl2_t;

static void* fdata(const char*path,int *size){
    int sz = 0;
    FILE*file = fopen(path,"rb");
    fseek(file,0,SEEK_END);
    sz = ftell(file);
    if(size) *size = sz;
    fseek(file,0,SEEK_SET);
    void* d = calloc(1,sz);
    fread(d,sz,1,file);
    fclose(file);
    return d;
}

int frame = 0;

static uint32_t tilePixel[256*800];
static uint8_t sdl_key[] = {
    SDL_SCANCODE_Z,
    SDL_SCANCODE_X,
    SDL_SCANCODE_SPACE,
    SDL_SCANCODE_RETURN,
    SDL_SCANCODE_RIGHT,
    SDL_SCANCODE_LEFT,
    SDL_SCANCODE_UP,
    SDL_SCANCODE_DOWN,
    SDL_SCANCODE_S,
    SDL_SCANCODE_A,
};
static int render(xgba_t*gba){
    frame++;
    //fprintf(stderr,"flush:%d\n",frame);
    //fflush(stderr);
    memset(tilePixel,0,sizeof(tilePixel));

    xgba_sdl2_t *sdl = (xgba_sdl2_t*)gba->render_data;
    uint8_t *vram = gba->vram;
    uint32_t *pal = gba->tilePal;
    int i = 0;
    for(i=0;i<=0x17FFF;i++){
        int x = i%256;
        int y = i/256;
        int tile_offset = x/8;      //最大0x20
        tile_offset += (y/8)*0x20;  //
        int tileX = x&0x7;
        int tileY = y&0x7;
        tile_offset *= 0x20;    //每一个tile为0x20大小
        tile_offset += tileY * 4;   //每一行偏移4个字节
        uint32_t tile_data = *(uint32_t*)(vram+tile_offset);
        int td = (tile_data>>(tileX*4))&0xf;
        tilePixel[y*256+x] = pal[td];
    }

    SDL_Rect rect;
    rect.x = 0;
    rect.y = 160;
    rect.w = 10;
    rect.h = 10;

    // for(i=0;i<0x100;i++){
    //     gba->screen[0][i] = 0xffffffff;
    // }
    SDL_UpdateTexture(sdl->texture,0,gba->screen[0],240*4);
    SDL_UpdateTexture(sdl->tileTexture,0,tilePixel,256*4);

    SDL_SetRenderDrawColor(sdl->renderer,0,0,0,0xff);
    SDL_RenderClear(sdl->renderer);
    rect.x = 0;
    rect.y = 0;
    rect.w = 240;
    rect.h = 160;
    SDL_RenderCopy(sdl->renderer,sdl->texture,0,&rect);

    rect.x = 240;
    rect.y = 0;
    rect.w = 256;
    rect.h = 800;
    SDL_RenderCopy(sdl->renderer,sdl->tileTexture,0,&rect);

    rect.x = 0;
    rect.y = 160;
    rect.w = 10;
    rect.h = 10;
    #if 1
    for(i=0;i<0x200;i++){
        uint32_t color = gba->tilePal[i];
        if((i%0x10)==0&&i){
            rect.x = 0;
            rect.y += 10;
        }
        SDL_SetRenderDrawColor(sdl->renderer,color&0xff,(color>>8)&0xff,(color>>16)&0xff,(color>>24)&0xff);
        SDL_RenderFillRect(sdl->renderer,&rect);
        rect.x += 10;
    }
    #endif
    SDL_RenderPresent(sdl->renderer);
    SDL_PollEvent(&sdl->event);
    if(sdl->event.type==SDL_QUIT){
        exit(0);
    }

    const uint8_t *key = SDL_GetKeyboardState(0);
    uint16_t key_value = 0;
    for(i=0;i<sizeof(sdl_key);i++){
        int scankey = sdl_key[i];
        if(key[scankey]){
            key_value |= 1<<i;
        }
    }
    //key_value |= 1<<3;
    // key_value |= 1<<0;
    if(key[SDL_SCANCODE_P]){
        while(1){
            SDL_PollEvent(&sdl->event);
            if(sdl->event.type==SDL_QUIT){
                return 0;
            }
            SDL_Delay(10);
        }
    }
    xgba_setkey(gba,key_value);

    return 0;
}

#undef main
int main(int argc,char**argv){
    int idx = 1;
    while(idx<argc){
        if(argv[idx][0]!='-'){
            params[0].proc(params+0,argc,argv,&idx);
        }
        else{
            game_param_t*p = params;
            int isp = 0;
            while(p->opt){
                if(!memcmp(p->opt,argv[idx],2)){
                    isp = 1;
                    p->proc(p,argc,argv,&idx);
                    break;
                }
                p++;
            }
            if(!isp){
                fprintf(stderr,"error option:%s",argv[idx]);
                return -1;
            }
        }
    }
    xgba_t gba;
    void *d = fdata(game_opt.rom,0);
    void*bios_d = fdata(game_opt.bios_file,0);


    if(d){
        memset(&gba,0,sizeof(gba));
        xgba_init(&gba);


        xgba_loadrom_free(&gba,d,free);
        xgba_loadbios(&gba,bios_d);

        xgba_sdl2_t sdl;
        memset(&sdl,0,sizeof(sdl));
        sdl.window = SDL_CreateWindow("gba",100,100,240+256,800,SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
        sdl.renderer = SDL_CreateRenderer(sdl.window,2,SDL_RENDERER_ACCELERATED);
        sdl.texture = SDL_CreateTexture(sdl.renderer,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,240,160);
        sdl.tileTexture = SDL_CreateTexture(sdl.renderer,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,256,800);
        gba.render_data = &sdl;
        gba.render = render;

        xgba_loop(&gba);

        xgba_clean(&gba);
        return 0;
    }
    return -1;
}
